热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

面试|newFixedThreadPool,newCachedThreadPool和newScheduledThreadPool的区别

前面主要分析ThreadPoolExecutor类的创建和运行过程,今天学习Executors类。1.Executors类和Executor类的关系Executo

前面主要分析ThreadPoolExecutor类的创建和运行过程,今天学习Executors类。


1.Executors类和Executor类的关系


  • Executor是含有执行提交Runnable任务的接口。如果你看了关于ThreadPoolExecutor类的分析,那么就知道线程池间接实现Executor接口。
  • Executors是一个工厂类,它能提供各种形式的线程池。

2.Executors类的作用

创建以下线程池和执行器。


2.1 newFixedThreadPool

创建一个线程池,该线程池重用在共享无界队列上运行的固定数量的线程。在任何时候,大多数nThreads线程都是活动的处理任务。如果在所有线程都处于活动状态时提交其他任务,它们将在队列中等待,直到线程可用为止。如果任何线程在关闭之前的执行过程中由于失败而终止,那么如果需要执行后续任务,则会替换一个新线程。池中的线程将一直存在,直到显式地执行execuorservice #shutdown关机。

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory);}

注意看到核心线程数和最大线程数都为nThreads&#xff0c;表明线程池内自始至终可用线程数为nThread&#xff1b;如果线程池内线程数已经达到nThreads&#xff0c;那么新到达的Runnable任务直接放入等待队列&#xff0c;由于不会再新建线程&#xff0c;所以为了保证池的可用性就使用无界等待队列。
注意提供重载的方法&#xff0c;提供自定义的线程工厂。


2.2 newCachedThreadPool

创建一个线程池&#xff0c;该线程池根据需要创建新线程&#xff0c;但在可用时将重用以前构造的线程。这些池通常会提高执行许多短期异步任务的程序的性能。如果可用&#xff0c;要执行的调用将重用以前构造的线程。如果没有可用的现有线程&#xff0c;将创建一个新线程并将其添加到池中。未使用60秒的线程将被终止并从缓存中删除。因此&#xff0c;长时间空闲的池不会消耗任何资源。注意&#xff0c;可以使用ThreadPoolExecutor构造函数创建具有相似属性但不同细节(例如超时参数)的池。

public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),threadFactory);}

注意该线程池核心线程数为0&#xff0c;最大线程池数为2^32-1&#xff0c;空闲线程只存活60秒&#xff1b;等待队列并不能存储Runnable任务&#xff0c;反而使得线程池继续创建线程来执行任务。


2.3 newScheduledThreadPool

创建一个线程池&#xff0c;该线程池可以调度在给定延迟之后运行的命令&#xff0c;或者定期执行命令。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);}

注意该线程池调用ScheduledThreadPoolExecutor类的构造方法。


2.4 newSingleThreadExecutor

创建一个执行器&#xff0c;该执行器使用一个工作线程操作一个无界队列。(但是请注意&#xff0c;如果这个线程在关闭之前的执行过程中由于失败而终止&#xff0c;那么如果需要执行后续任务&#xff0c;将会有一个新的线程替代它。)任务保证按顺序执行&#xff0c;并且在任何给定时间都不会有多个任务处于活动状态。与其他等价的newFixedThreadPool(1)不同&#xff0c;返回的执行器保证不可重新配置以使用其他线程。

public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory));}

此刻我们注意到FinalizableDelegatedExecutorService包装ThreadPoolExecutor对象&#xff0c;其实FinalizableDelegatedExecutorService继承自DelegatedExecutorService&#xff0c;该类是只公开ExecutorService实现的ExecutorService方法的包装器类。


2.5 newSingleThreadScheduledExecutor

创建一个单线程执行器&#xff0c;该执行器可以安排命令在给定的延迟之后运行&#xff0c;或者定期执行。(但是请注意&#xff0c;如果这个线程在关闭之前的执行过程中由于失败而终止&#xff0c;那么如果需要执行后续任务&#xff0c;将会有一个新的线程替代它。)任务保证按顺序执行&#xff0c;并且在任何给定时间都不会有多个任务处于活动状态。与其他等价的newScheduledThreadPool(1)不同&#xff0c;返回的执行器保证不可重新配置以使用其他线程。

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
}public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, threadFactory));}

提供两种线程工厂


  • DefaultThreadFactory&#xff1a;默认的线程工厂

static class DefaultThreadFactory implements ThreadFactory {private static final AtomicInteger poolNumber &#61; new AtomicInteger(1);private final ThreadGroup group;private final AtomicInteger threadNumber &#61; new AtomicInteger(1);private final String namePrefix;DefaultThreadFactory() {SecurityManager s &#61; System.getSecurityManager();group &#61; (s !&#61; null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();namePrefix &#61; "pool-" &#43;poolNumber.getAndIncrement() &#43;"-thread-";}public Thread newThread(Runnable r) {Thread t &#61; new Thread(group, r,namePrefix &#43; threadNumber.getAndIncrement(),0);if (t.isDaemon())t.setDaemon(false); // 非守护线程if (t.getPriority() !&#61; Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY); // 优先级return t;}}

默认的线程工厂通过newThread(Runnable)方法创建新的线程。并确定新线程的线程组&#xff0c;默认名字(格式&#xff1a;pool-poolNumber-thread-threadNumber)&#xff1b;设置为非守护线程&#xff0c;便于销毁&#xff1b;设置新线程的优先级。


  • PrivilegedThreadFactory&#xff1a;享有特权的线程工厂。
    它可以捕获访问控制上下文acc和类加载器ccl。

static class PrivilegedThreadFactory extends DefaultThreadFactory {private final AccessControlContext acc;private final ClassLoader ccl;PrivilegedThreadFactory() {super();SecurityManager sm &#61; System.getSecurityManager();if (sm !&#61; null) {// Calls to getContextClassLoader from this class// never trigger a security check, but we check// whether our callers have this permission anyways.sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);// Fail fastsm.checkPermission(new RuntimePermission("setContextClassLoader"));}this.acc &#61; AccessController.getContext();this.ccl &#61; Thread.currentThread().getContextClassLoader();}public Thread newThread(final Runnable r) {return super.newThread(new Runnable() {public void run() {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {Thread.currentThread().setContextClassLoader(ccl);r.run();return null;}}, acc);}});}}

在创建新线程的时候设置当前线程的控制上下文和类加载器与调用该线程工厂的线程的控制上下文和类加载器一致。


推荐阅读
  • 本文介绍了如何在 Spring Boot 项目中使用 spring-boot-starter-quartz 组件实现定时任务,并将 cron 表达式存储在数据库中,以便动态调整任务执行频率。 ... [详细]
  • 兆芯X86 CPU架构的演进与现状(国产CPU系列)
    本文详细介绍了兆芯X86 CPU架构的发展历程,从公司成立背景到关键技术授权,再到具体芯片架构的演进,全面解析了兆芯在国产CPU领域的贡献与挑战。 ... [详细]
  • 如何利用Java 5 Executor框架高效构建和管理线程池
    Java 5 引入了 Executor 框架,为开发人员提供了一种高效管理和构建线程池的方法。该框架通过将任务提交与任务执行分离,简化了多线程编程的复杂性。利用 Executor 框架,开发人员可以更灵活地控制线程的创建、分配和管理,从而提高服务器端应用的性能和响应能力。此外,该框架还提供了多种线程池实现,如固定线程池、缓存线程池和单线程池,以适应不同的应用场景和需求。 ... [详细]
  • 本文将介绍如何在混合开发(Hybrid)应用中实现Native与HTML5的交互,包括基本概念、学习目标以及具体的实现步骤。 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • com.hazelcast.config.MapConfig.isStatisticsEnabled()方法的使用及代码示例 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 本文总结了一些开发中常见的问题及其解决方案,包括特性过滤器的使用、NuGet程序集版本冲突、线程存储、溢出检查、ThreadPool的最大线程数设置、Redis使用中的问题以及Task.Result和Task.GetAwaiter().GetResult()的区别。 ... [详细]
  • 本文深入解析了JDK 8中HashMap的源代码,重点探讨了put方法的工作机制及其内部参数的设定原理。HashMap允许键和值为null,但键为null的情况只能出现一次,因为null键在内部通过索引0进行存储。文章详细分析了capacity(容量)、size(大小)、loadFactor(加载因子)以及红黑树转换阈值的设定原则,帮助读者更好地理解HashMap的高效实现和性能优化策略。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 深入探索HTTP协议的学习与实践
    在初次访问某个网站时,由于本地没有缓存,服务器会返回一个200状态码的响应,并在响应头中设置Etag和Last-Modified等缓存控制字段。这些字段用于后续请求时验证资源是否已更新,从而提高页面加载速度和减少带宽消耗。本文将深入探讨HTTP缓存机制及其在实际应用中的优化策略,帮助读者更好地理解和运用HTTP协议。 ... [详细]
  • 本文详细介绍了在Linux系统上编译安装MySQL 5.5源码的步骤。首先,通过Yum安装必要的依赖软件包,如GCC、GCC-C++等,确保编译环境的完备。接着,下载并解压MySQL 5.5的源码包,配置编译选项,进行编译和安装。最后,完成安装后,进行基本的配置和启动测试,确保MySQL服务正常运行。 ... [详细]
  • 开发日志:201521044091 《Java编程基础》第11周学习心得与总结
    开发日志:201521044091 《Java编程基础》第11周学习心得与总结 ... [详细]
  • 在Android开发中,BroadcastReceiver(广播接收器)是一个重要的组件,广泛应用于多种场景。本文将深入解析BroadcastReceiver的工作原理、应用场景及其具体实现方法,帮助开发者更好地理解和使用这一组件。通过实例分析,文章详细探讨了静态广播的注册方式、生命周期管理以及常见问题的解决策略,为开发者提供全面的技术指导。 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
author-avatar
一啖过
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有